#ifndef __EXL_TM_LIB__
#define __EXL_TM_LIB__


#include <windows.h>
#include <iostream>
#include <sstream>


namespace exl {
namespace timer {



class Timer
{
	static bool started;
	static unsigned __int64 freq;	// frequencia (Hz)
	static double s_period;			// periodo em segundos (inverso da frequencia)
	static double ms_period;		// periodo em milissegundos (inverso da frequencia)
	static double us_period;		// periodo em microssegundos (inverso da frequencia)

public:
	static double getFrequency();
	static unsigned long getMillisecondsCount();
	static unsigned __int64 getMicrosecondsCount();
};


/**
 * Cronometro
 */
class Chronometer
{
	unsigned __int64 nStartTime;//us
	unsigned __int64 nCreateTime;//us
	unsigned __int64 nDeltaTime;//us
	bool running;

public:
	Chronometer() : nStartTime(0), nCreateTime(Timer::getMicrosecondsCount()), nDeltaTime(0), running(false) { }

	inline void start()
	{
		if (!running)
		{
			nStartTime = Timer::getMicrosecondsCount();
			running = true;
		}
	}

	inline void stop()
	{
		nDeltaTime += Timer::getMicrosecondsCount() - nStartTime;
		running = false;
	}

	inline void reset()
	{
		nStartTime = 0;
		nDeltaTime = 0;
		running = false;
	}

	/**
	 * Retorna tempo decorrido desde a criacao do objeto
	 */
	inline unsigned __int64 getTotalMicroseconds() const { return (Timer::getMicrosecondsCount() - nCreateTime); }
	inline unsigned int getTotalMilliseconds() const { return unsigned int(getTotalMicroseconds() / 1000); }
	inline double getTotalSeconds() const { return double(getTotalMicroseconds()) / 1000000.0; }

	/**
	 * Retorna tempo cronometrado
	 */
	inline unsigned __int64 getTimeMicroseconds() const { return nDeltaTime; }
	inline unsigned int getTimeMilliseconds() const { return unsigned int(nDeltaTime / 1000); }
	inline double getTimeSeconds() const { return double(nDeltaTime) / 1000000.0; }

};



class AverageChrono : public Chronometer
{
public:
	int id;
	int cmtCount;
	double cmtSum;

	AverageChrono(int id = -1) : id(id), cmtCount(0), cmtSum(0.0f) {}
/*
	inline void reset()
	{
		this->Chronometer::reset();
		cmtCount = 0;
	}
*/
	inline void operator += (double t) { cmtSum += t; cmtCount++; }
	inline double getAverage() { return (cmtSum + getTimeSeconds()) / cmtCount; }

	inline void stop()
	{
		this->Chronometer::stop();
		cmtCount++;
	}

	std::string toString()
	{
		std::ostringstream os;
		os << " { id=" << id << "   media=" << getAverage() << " s   count=" << cmtCount << " }";
		return os.str();
	}
};


}} // exl::timer

#endif
